﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using ImageCombinerCore;
using System.Threading;
using System.IO;
using System.Drawing.Imaging;
using Microsoft.Win32;

namespace ImageCombinerProj
{
    public partial class MainWindow : Window
    {
        ImageCombiner mImageCombiner;
        ImageInfoStruct[] mImageInfoArr;
        bool mIsRefreshingPreviewImage;


        public MainWindow()
        {
            InitializeComponent();

            mImageCombiner = new ImageCombiner();
        }

        void RefreshBaseInfo(string outputImagePath)
        {
            pathTextBlock.Text = outputImagePath;
        }

        void RefreshPreviewImage()
        {
            if (mIsRefreshingPreviewImage) return;

            ThreadPool.QueueUserWorkItem(RefreshPreviewImage_ThreadCBMethod);
        }

        void RefreshPreviewImage_ThreadCBMethod(Object param)
        {
            mIsRefreshingPreviewImage = true;
            var finalImage = mImageCombiner.ExecuteCombine();
            if (finalImage != null)
            {
                Dispatcher.Invoke(new Action(() =>
                {
                    previewImage.Source = ConvertDrawingImageToImageSource(finalImage);
                }));
            }
            else
            {
                Dispatcher.Invoke(new Action(() =>
                {
                    previewImage.Source = null;
                }));
            }

            mIsRefreshingPreviewImage = false;
        }

        void InitImageInfoList()
        {
            InitImageInfoList(mImageCombiner.GetCombineInfoArr().Reverse().ToArray());
        }

        void InitImageInfoList(CombineInfoStruct[] combineInfoArr)
        {
            mImageInfoArr = new ImageInfoStruct[combineInfoArr.Length];

            for (int i = 0; i < mImageInfoArr.Length; i++)
            {
                var item = new ImageInfoStruct();

                item.BlendMode = combineInfoArr[i].BlendMode;
                item.FileName = System.IO.Path.GetFileNameWithoutExtension(combineInfoArr[i].ImagePath);
                item.Image = new Bitmap(combineInfoArr[i].ImagePath);
                item.Opacity = combineInfoArr[i].Opacity;
                item.AttachData = combineInfoArr[i];

                mImageInfoArr[i] = item;
            }

            RefreshImageInfoList(mImageInfoArr);
        }

        void RefreshImageInfoList()
        {
            RefreshImageInfoList(mImageInfoArr);
        }

        void RefreshImageInfoList(ImageInfoStruct[] imageInfoArr)
        {
            imageList.Items.Clear();

            for (int i = 0; i < imageInfoArr.Length; i++)
            {
                var item = imageInfoArr[i];

                ListView listView = new ListView();
                listView.MinWidth = 161;
                var stackPanel = new StackPanel();
                stackPanel.Orientation = Orientation.Horizontal;
                var image = ConvertDrawingImageToImageSource(item.Image);
                var smallImage = new System.Windows.Controls.Image() { Source = image, MaxHeight = 20, MaxWidth = 32 };
                stackPanel.Children.Add(smallImage);
                stackPanel.Children.Add(new TextBox() { Text = item.FileName, MinWidth = 130, MaxWidth = 130 });
                var removeItemBtn = new Button() { Content = "X", MinWidth = 20, MaxWidth = 20 };
                removeItemBtn.DataContext = item;
                removeItemBtn.Click += OnCombineListInfoBtnClickedCB;
                stackPanel.Children.Add(removeItemBtn);
                listView.Items.Add(stackPanel);

                var stackPanel2 = new StackPanel();
                stackPanel2.MinWidth = 161;
                stackPanel2.Orientation = Orientation.Horizontal;
                stackPanel2.Children.Add(new Label() { Content = I18N._("Opacity") });
                stackPanel2.Children.Add(new Label() { Content = item.Opacity.ToString(), MaxWidth = 30, MinWidth = 30, Width = 30 });
                var opacitySlider = new Slider() { Minimum = 0, Maximum = 1, Value = item.Opacity, MinWidth = 95, MaxWidth = 95, Width = 95 };
                opacitySlider.DataContext = item;
                opacitySlider.AddHandler(Slider.MouseUpEvent, new RoutedEventHandler(OnOpacitySliderValueChanged), true);

                stackPanel2.Children.Add(opacitySlider);
                listView.Items.Add(stackPanel2);

                var stackPanel3 = new StackPanel();
                stackPanel3.Orientation = Orientation.Horizontal;
                stackPanel3.Children.Add(new Label() { Content = I18N._("BlendMode") });
                var blendModeComboBox = new ComboBox();
                blendModeComboBox.MinWidth = 95;
                blendModeComboBox.Items.Add(new Label() { Content = I18N._("Normal") });
                blendModeComboBox.Items.Add(new Label() { Content = I18N._("Darken") });
                blendModeComboBox.Items.Add(new Label() { Content = I18N._("Lighten") });
                blendModeComboBox.Items.Add(new Label() { Content = I18N._("Overlay") });
                blendModeComboBox.SelectedItem = blendModeComboBox.Items
                    .Cast<Label>()
                    .FirstOrDefault(m => m.Content.ToString() == I18N._(item.BlendMode.ToString()));
                blendModeComboBox.DataContext = item;
                blendModeComboBox.AddHandler(ComboBox.SelectionChangedEvent, new RoutedEventHandler(OnBlendModeComboBoxChanged));

                stackPanel3.Children.Add(blendModeComboBox);
                listView.Items.Add(stackPanel3);

                imageList.Items.Add(listView);
            }
        }

        ImageSource ConvertDrawingImageToImageSource(System.Drawing.Image sourceImage)
        {
            var memoryStream = new MemoryStream();
            sourceImage.Save(memoryStream, ImageFormat.Jpeg);
            memoryStream.Position = 0;
            var imageSource = new BitmapImage();
            imageSource.BeginInit();
            imageSource.StreamSource = memoryStream;
            imageSource.EndInit();

            return imageSource;
        }

        void OnWindowLoaded(object sender, RoutedEventArgs e)
        {
            //I18N.DeserializeFromFile("i18n/zh_CN_i10n");
            I18N.DeserializeFromFile("i18n/en_US_i10n");

            combinedDeleteSourceImages.Content = I18N._("Combined Delete Source Images");
            outputPath.Content = I18N._("Output Path");
            goBtn.Content = I18N._("GO");
            loadPresetBtn.Content = I18N._("Load Preset");
            savePresetBtn.Content = I18N._("Save Preset");
            clearImageBtn.Content = I18N._("Clear Images");
            selectDirectoryBtn.Content = I18N._("Select Directory...");
        }

        void OnWindowClosed(object sender, EventArgs e)
        {
            if (mImageInfoArr != null)
            {
                for (int i = 0; i < mImageInfoArr.Length; i++)
                {
                    var item = mImageInfoArr[i];

                    if (item.Image != null)
                        item.Image.Dispose();
                }
            }
        }

        void OnCombineListInfoBtnClickedCB(object sender, RoutedEventArgs e)
        {
            var btn = sender as Button;
            var imageInfoStruct = btn.DataContext as ImageInfoStruct;
            var combineInfoStruct = imageInfoStruct.AttachData as CombineInfoStruct;

            mImageCombiner.RemoveCombineInfo(combineInfoStruct);

            InitImageInfoList();
            RefreshPreviewImage();
        }

        void OnBlendModeComboBoxChanged(object sender, RoutedEventArgs e)
        {
            var comboBox = sender as ComboBox;
            var imageInfo = comboBox.DataContext as ImageInfoStruct;
            var combineInfo = imageInfo.AttachData as CombineInfoStruct;
            var comboBoxArr = comboBox.Items.Cast<Label>().ToArray();

            var selectedLabel = comboBox.SelectedItem as Label;

            if (selectedLabel == null) return;

            var content = selectedLabel.Content.ToString();

            if (content == I18N._("Normal")) combineInfo.BlendMode = BlendModeEnum.Normal;
            else if (content == I18N._("Lighten")) combineInfo.BlendMode = BlendModeEnum.Lighten;
            else if (content == I18N._("Darken")) combineInfo.BlendMode = BlendModeEnum.Darken;
            else if (content == I18N._("Overlay")) combineInfo.BlendMode = BlendModeEnum.Overlay;

            imageInfo.BlendMode = combineInfo.BlendMode;
            RefreshImageInfoList();
            RefreshPreviewImage();
        }

        void OnOpacitySliderValueChanged(object sender, RoutedEventArgs e)
        {
            var slider = sender as Slider;
            var imageInfo = slider.DataContext as ImageInfoStruct;
            var combineInfo = imageInfo.AttachData as CombineInfoStruct;

            combineInfo.Opacity = (float)slider.Value;
            imageInfo.Opacity = combineInfo.Opacity;

            RefreshImageInfoList();
            RefreshPreviewImage();
        }

        void OnGOBtnClickedCB(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < mImageInfoArr.Length; i++)
            {
                var item = mImageInfoArr[i];
                item.Image.Dispose();
            }

            var result = mImageCombiner.ExecuteCombineAndSaved();

            if (result)
            {
                mImageCombiner.ClearCombineInfo();
                InitImageInfoList();
                RefreshPreviewImage();
                MessageBox.Show(I18N._("Save Image Completed!"));
            }
            else
            {
                MessageBox.Show(I18N._("Save Image Failure!"));
            }
        }

        void OnLoadPresetBtnClickedCB(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.Title = I18N._("Select Preset");
            openFileDialog.Filter = "*.xml|*.xml";
            openFileDialog.FileName = string.Empty;
            openFileDialog.FilterIndex = 1;
            openFileDialog.RestoreDirectory = true;
            openFileDialog.DefaultExt = "xml";
            var result = openFileDialog.ShowDialog();

            if (!result.HasValue || result.Value == false) return;

            var presetFullPath = openFileDialog.FileName;

            mImageCombiner.LoadPreset(presetFullPath);

            InitImageInfoList();
            RefreshPreviewImage();
            RefreshBaseInfo(mImageCombiner.OutputImagePath);
        }

        void OnSavePresetBtnClickedCB(object sender, RoutedEventArgs e)
        {
            var saveFileDialog = new System.Windows.Forms.SaveFileDialog();
            saveFileDialog.Title = I18N._("Select Preset");
            saveFileDialog.Filter = "xml|*.xml";
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.RestoreDirectory = true;
            saveFileDialog.DefaultExt = "xml";
            var result = saveFileDialog.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.Cancel) return;

            var savePresetDir = saveFileDialog.FileName;

            mImageCombiner.SavePreset(savePresetDir);
            System.Windows.MessageBox.Show(I18N._("Save Preset Completed!"));
        }

        void OnSelectOutputPathBtnClickedCB(object sender, RoutedEventArgs e)
        {
            var saveFileDialog = new System.Windows.Forms.SaveFileDialog();
            saveFileDialog.Title = I18N._("Select Output Path");
            saveFileDialog.Filter = "jpg|*.jpg";
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.RestoreDirectory = true;
            saveFileDialog.DefaultExt = "jpg";
            var result = saveFileDialog.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.Cancel) return;

            mImageCombiner.OutputImagePath = saveFileDialog.FileName;
            RefreshBaseInfo(mImageCombiner.OutputImagePath);
        }

        void OnSelectDirectoryBtnClickedCB(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.Multiselect = true;
            openFileDialog.Title = I18N._("Select Image");
            openFileDialog.Filter = "jpg|*.jpg|jpeg|*.jpeg";
            openFileDialog.FilterIndex = 1;
            openFileDialog.RestoreDirectory = true;
            openFileDialog.DefaultExt = "jpg";
            var result = openFileDialog.ShowDialog();

            if (!result.HasValue || result.Value == false) return;

            mImageCombiner.ClearCombineInfo();

            var presetFullPath = openFileDialog.FileName;
            for (int i = 0; i < openFileDialog.FileNames.Length; i++)
            {
                var file = openFileDialog.FileNames[i];

                mImageCombiner.AddCombineInfo(new CombineInfoStruct() { ImagePath = file, BlendMode = BlendModeEnum.Normal, Opacity = 1 });
            }

            InitImageInfoList();
            RefreshPreviewImage();
        }

        void OnCombinedDeleteSourceImagesTogClickedCB(object sender, RoutedEventArgs e)
        {
            mImageCombiner.SavedDeleteSourceImages = combinedDeleteSourceImages.IsChecked.GetValueOrDefault();
        }

        void OnClearImageBtnClickedCB(object sender, RoutedEventArgs e)
        {
            mImageCombiner.ClearCombineInfo();
            InitImageInfoList();
            RefreshPreviewImage();
        }
    }
}
